package indi.zhifa.core.mpenhance.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import indi.zhifa.core.mpenhance.properties.MetaObjectHandlerProperty;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;

import java.time.LocalDateTime;


@Slf4j
public abstract class BaseMetaObjectHandler implements MetaObjectHandler, ApplicationContextAware {

    protected Long SYS_ID;
    protected String SYS_NAME;

    protected String createTimeStr;
    protected String createByStr;
    protected String createByNameStr;
    protected String versionStr;

    protected String modifyTimeStr;
    protected String modifyByStr;
    protected String modifyByNameStr;

    boolean hasInit = false;

    protected ApplicationContext mApplicationContext;

    @Override
    public void setApplicationContext(ApplicationContext pApplicationContext){
        mApplicationContext = pApplicationContext;
    }


//    public BaseMetaObjectHandler(MetaObjectHandlerProperty pMetaObjectHandlerProperty){
//        SYS_ID = pMetaObjectHandlerProperty.getSysId();
//        SYS_NAME = pMetaObjectHandlerProperty.getSysName();
//        createTimeStr = pMetaObjectHandlerProperty.getCreateTimeStr();
//        createByStr = pMetaObjectHandlerProperty.getCreateByStr();
//        createByNameStr = pMetaObjectHandlerProperty.getCreateByNameStr();
//        versionStr = pMetaObjectHandlerProperty.getVersionStr();
//        modifyTimeStr = pMetaObjectHandlerProperty.getModifyTimeStr();
//        modifyByStr = pMetaObjectHandlerProperty.getModifyByStr();
//        modifyByNameStr = pMetaObjectHandlerProperty.getModifyByNameStr();
//    }


    public void initWithMetaObject(){
        MetaObjectHandlerProperty metaObjectHandlerProperty = mApplicationContext.getBean(MetaObjectHandlerProperty.class);
        SYS_ID = metaObjectHandlerProperty.getSysId();
        SYS_NAME = metaObjectHandlerProperty.getSysName();
        createTimeStr = metaObjectHandlerProperty.getCreateTimeStr();
        createByStr = metaObjectHandlerProperty.getCreateByStr();
        createByNameStr = metaObjectHandlerProperty.getCreateByNameStr();
        versionStr = metaObjectHandlerProperty.getVersionStr();
        modifyTimeStr = metaObjectHandlerProperty.getModifyTimeStr();
        modifyByStr = metaObjectHandlerProperty.getModifyByStr();
        modifyByNameStr = metaObjectHandlerProperty.getModifyByNameStr();
        hasInit = true;
    }


    protected boolean checkFieldNull(MetaObject pMetaObject, String pField){
        if(pMetaObject.hasSetter(pField)){
            Object orgVal = pMetaObject.getValue(pField);
            if(null == orgVal){
                return true;
            }
        }
        return false;
    }

    protected void insertVersion(MetaObject pMetaObject){
        if(checkFieldNull(pMetaObject,versionStr)){
            this.strictInsertFill(pMetaObject,versionStr,()-> 0, Integer.class);
        }
    }

    protected void insertCreateTime(MetaObject pMetaObject){
        if(checkFieldNull(pMetaObject,createTimeStr)){
            this.strictInsertFill(pMetaObject,createTimeStr,()-> LocalDateTime.now(),LocalDateTime.class);
        }
    }

    protected abstract void insertCreateBy(MetaObject pMetaObject);

    protected abstract void insertCreateByName(MetaObject pMetaObject);

    abstract protected void otherInsertFill(MetaObject pMetaObject);

    abstract protected boolean hasTokenObject();

    @Override
    public void insertFill(MetaObject pMetaObject) {

        if(!hasInit){
            initWithMetaObject();
        }

        insertCreateTime(pMetaObject);
        insertVersion(pMetaObject);
        if(hasTokenObject()){
            try{
                if(checkFieldNull(pMetaObject,createByNameStr)){
                    insertCreateBy(pMetaObject);
                }
                if(checkFieldNull(pMetaObject,createByNameStr)){
                    insertCreateByName(pMetaObject);
                }

            }catch (Exception ex){
                log.error("insertFill 出现异常",ex);
            }
        }else{
            if(checkFieldNull(pMetaObject,createByStr)){
                this.strictInsertFill(pMetaObject,createByStr,()->SYS_ID,Long.class);
            }
            if(checkFieldNull(pMetaObject,createByNameStr)){
                this.strictInsertFill(pMetaObject,createByNameStr,()->SYS_NAME,String.class);
            }
        }
        otherInsertFill(pMetaObject);
    }

    protected void updateModifyTime(MetaObject pMetaObject){
        if(checkFieldNull(pMetaObject,modifyTimeStr)){
            this.strictUpdateFill(pMetaObject,modifyTimeStr,()-> LocalDateTime.now(),LocalDateTime.class);
        }
    }

    protected abstract void updateModifyBy(MetaObject pMetaObject);

    protected abstract void updateModifyByName(MetaObject pMetaObject);

    abstract protected void otherUpdateFill(MetaObject pMetaObject);


    @Override
    public void updateFill(MetaObject pMetaObject) {

        if(!hasInit){
            initWithMetaObject();
        }

        updateModifyTime(pMetaObject);
        if(hasTokenObject()){
            try{
                if(checkFieldNull(pMetaObject,modifyByStr)){
                    updateModifyBy(pMetaObject);
                }
                if(checkFieldNull(pMetaObject,modifyByNameStr)){
                    updateModifyByName(pMetaObject);
                }
            }catch (Exception ex){
                log.error("updateFill 出现异常",ex);
            }
        }else{
            if(checkFieldNull(pMetaObject,modifyByStr)){
                this.strictUpdateFill(pMetaObject,modifyByStr,()->SYS_ID,Long.class);
            }
            if(checkFieldNull(pMetaObject,modifyByNameStr)){
                this.strictUpdateFill(pMetaObject,modifyByNameStr,()->SYS_NAME,String.class);
            }
        }
        otherUpdateFill(pMetaObject);
    }
}
